import qs from 'qs'
import G from '../global'

const isObject = o => o !== null && typeof o === 'object'
const stringify = object => qs.stringify(object)
const hasProp = (o, k) => Object.prototype.hasOwnProperty.call(o, k)

const RESOLVE_KEY = 'RESOLVE_WITH_FULL_RESPONSE'
const hasResolve = o => isObject(o) && hasProp(o, RESOLVE_KEY)
const getResolve = o => isObject(o) && o[RESOLVE_KEY]

function fetch(url, options) {
  return new Promise((resolve, reject) => {
    G.request({
      url,
      data: options.body || '',
      header: options.headers || {},
      method: options.method,
      dataType: 'json',
      success: resolve,
      fail: reject
    })
  })
}

export default async function request(initUrl, initOptions) {
  let resolveWithFullResponse = false

  if (hasResolve(initOptions.body)) {
    resolveWithFullResponse = getResolve(initOptions.body)
    delete initOptions.data[RESOLVE_KEY]
  }
  if (hasResolve(initOptions.data)) {
    resolveWithFullResponse = getResolve(initOptions.data)
    delete initOptions.data[RESOLVE_KEY]
  }

  const options = Object.assign(
    { method: 'GET', credentials: 'include' },
    initOptions
  )

  // header content-type
  const headers = isObject(options.headers) ? options.headers : {}
  if (!Object.keys(headers).some(k => k.toLowerCase() === 'content-type')) {
    headers['Content-Type'] = 'application/x-www-form-urlencoded'
  }

  // method body
  const method = String(options.method).toUpperCase()
  if (!['GET', 'POST', 'PUT', 'DELETE'].some(k => k === method)) {
    throw new Error('fetch method 参数必须为 GET POST PUT DELETE 之一')
  }

  let url = initUrl
  let body = options.body || ''

  if (method === 'GET' && isObject(options.data)) {
    const restQueryStr = stringify(options.data)
    if (restQueryStr) {
      url = `${initUrl}&${restQueryStr}`
    }
    delete options.data
  } else if (method === 'POST') {
    if (isObject(options.data)) {
      body = stringify(options.data)
      delete options.data
    } else if (isObject(options.body)) {
      body = stringify(options.body)
    }
  }

  options.headers = headers
  options.method = method

  if (['POST', 'PUT'].indexOf(method) !== -1) {
    options.body = body
  }

  const toErr = ({ message, code }) => {
    const e = new Error(message)
    e.msg = message
    e.code = code
    return e
  }

  // 请求
  const res = await fetch(url, options)
  // console.log(res)
  if (res.statusCode === 200) {
    const data = res.data
    if (data.code === 200) {
      return resolveWithFullResponse ? data : data.result
    }
    throw toErr({ message: data.msg, code: data.code })
  }
  throw toErr({ message: `状态码错误：${res.statusCode}, 请稍后重试`, code: res.status })
}

const makeMethod = method => (url, options = {}) =>
  request(url, Object.assign({ method }, options))
export const get = makeMethod('GET')
export const post = makeMethod('POST')
